<?php

namespace End01here\EasySms;


use End01here\EasySms\Exceptions\CodeErrorException;
use Illuminate\Support\Facades\Redis;

/**
 * 获取短信发送服务对象
 * Class EasySmsService
 * @package End01here\EasySms
 */
class CodeSever
{

    private $code = '';
    private $code_type = '';
    private $code_num = '';
    private $phone = '';
    private $code_name = '';
    private $error_msg = '';
    private $success_msg = '';
    private $send_type = 'default';

    /**
     * 创建code对象
     * CodeSever constructor.
     * @param PhoneNumberServer $phone
     * @param string $code_type
     * @param int $code_num
     */
    public function __construct(PhoneNumberServer $phone, $code_type = 'send_code', $code_num = 4)
    {
        $this->phone = $phone;
        $this->code_type = $code_type;
        if ($code_num < 4) $code_num = 4;
        $this->code_num = $code_num;
    }

    /**
     * 生成code
     * @param string $send_type
     * @return $this
     * @throws CodeErrorException
     */
    function setCode($send_type = 'default')
    {
        $this->send_type = $send_type;
        $cache_type = config('easy_sms')['cache_type'];
        $mix_time = config('easy_sms')['mix_time'];
        if ($cache_type == 'file') {
            $code_info = $this->getFileCode();
        } else {
            $code_info = $this->getRedisCode();
        }
        $time = time();
        if (!empty($code_info)) {
            //发送时间低于最低重发时间时，抛出异常
            if ($code_info['send_time'] + $mix_time > $time) {
                throw new CodeErrorException('短信发送超频，请' . ($code_info['send_time'] + $mix_time - $time) . '再试',0);
            }
        }
        //生成随机数
        $this->rand();
        //存储code信息
        if ($cache_type == 'file') {
            $this->setFileCode();
        } else {
            $this->setRedisCode();
        }
        return $this;
    }

    /**
     * 获取已生成的随机数
     * @return string
     * @throws CodeErrorException
     */
    function getCode()
    {
        if (empty($this->code)) $this->setCode();
        return $this->code;
    }

    /**
     * 验证码验证
     * @param $code
     * @param $send_type
     * @return bool
     */
    function verifyCode($code, $send_type = 'default')
    {
        $this->send_type = $send_type;
        $cache_type = config('easy_sms')['cache_type'];
        //是否开启测试验证码
        $is_current = config('easy_sms')['is_current'];
        $current_code = config('easy_sms')['current_code'];
        if ($is_current && $code == $current_code) {
            $this->success_msg = '验证成功';
            return true;
        }
        if ($cache_type == 'file') {
            $code_info = $this->getFileCode();
        } else {
            $code_info = $this->getRedisCode();
        }
        if (empty($code_info)) {
            $this->error_msg = '验证码已过期';
            return false;
        }
        $cache_time = config('easy_sms')['cache_time'] * 60;
        $time = time();
        if (empty($cache_time)) $cache_time = 600;
        if ($code_info['send_time'] + $cache_time < $time) {
            $this->error_msg = '验证码已过期';
            return false;
        }
        if ($code != $code_info['code']) {
            $this->error_msg = '验证码错误';
            return false;
        }
        $this->success_msg = '验证成功';
        if ($cache_type == 'file') {
            $this->delFileCode();
        } else {
            $this->delRedisCode();
        }
        return true;
    }


    /**
     * 清楚文件夹缓存信息
     */
    static function clearCode()
    {
        $path_url = __DIR__ . '/Cache/';
        $dh = opendir($path_url);
        $cache_time = config('easy_sms')['cache_time'] * 60;
        $time = time();
        if (empty($cache_time)) $cache_time = 600;
        while ($file = readdir($dh)) {
            if ($file != "." && $file != "..") {
                $fullpath = $path_url . "/" . $file;
                if (is_file($fullpath) && (filemtime($fullpath) + $cache_time) < $time) {
                    unlink($fullpath);
                }
            }
        }
        closedir($dh);
    }

    /**
     * 生成随机数
     */
    protected function rand()
    {
        $sms = null;
        for ($i = 0; $i < $this->code_num; ++$i) {
            $sms[] = mt_rand(0, 9);      // 随机 0-9
        }
        $this->code = join('', $sms);
    }

    /**
     * 获取文件存储的数据
     * @return array|mixed
     */
    function getFileCode()
    {
        $file_name = $this->getCodeName() . '.txt';
        $path_url = __DIR__ . '/Cache/' . $file_name;
        if (!is_file($path_url)) return [];
        $code_info = file_get_contents($path_url);
        $code_info = json_decode($code_info, true);
        return $code_info;
    }

    /**
     * 文件存储随机数
     */
    private function setFileCode()
    {
        $file_name = $this->getCodeName() . '.txt';
        $path_url = __DIR__ . '/Cache/' . $file_name;
        file_put_contents($path_url, json_encode(['code' => $this->code, 'send_time' => time()]));
    }

    /**
     * 清除文件验证码
     */
    private function delFileCode()
    {
        $file_name = $this->getCodeName() . '.txt';
        $path_url = __DIR__ . '/Cache/' . $file_name;
        if (is_file($path_url)) {
            unlink($path_url);
        }
    }

    /**
     * 获取redis中存储的数据
     * @return array|mixed
     */
    function getRedisCode()
    {
        $key_name = $this->getCodeName();
        $code_info = Redis::get($key_name);
        if (empty($code_info)) return [];
        $code_info = json_decode($code_info, true);
        return $code_info;
    }

    /**
     * redis存储验证码
     */
    private function setRedisCode()
    {
        $key_name = $this->getCodeName();
        $cache_num = config('easy_sms')['cache_time'] * 60;
        if (empty($cache_num)) $cache_num = 600;
        Redis::setex($key_name, $cache_num, json_encode(['code' => $this->code, 'send_time' => time()]));
    }

    /**
     * 清除验证码
     */
    private function delRedisCode()
    {
        $key_name = $this->getCodeName();
        Redis::set($key_name, null);
    }

    /**
     * 拼接验证码存储名称
     * @return string
     */
    function getCodeName()
    {
        if (empty($this->code_name)) $this->code_name = $this->phone->getNumber() . '_' . $this->code_type;
        return $this->code_name . $this->send_type;
    }

    /**
     * 获取错误信息
     * @return string
     */
    function getErrorMsg()
    {
        return $this->error_msg;
    }

    /**
     * 获取成功信息
     * @return string
     */
    function getSuccessMsg()
    {
        return $this->success_msg;
    }


}
